import config from '@/common/config.js';
import { isLogin } from '@/common/util';
import { reportEvent } from "@/common/eventUtil";
import {getStorage, removeAllStroage} from '@/common/storage';

// request 配置方法
const requestSetting = (request) => {
  console.log('config', config);
    // http全局配置
    request.setConfig({
      baseUrl: config.BASEURL,
      isToken: true,
      isLoading: false,
      header: {
        "Content-Type": "application/json",
      },
      localDebug: config.LOCAL_DEBUG,
    });

    // 设置请求拦截器
    // 配置参数和全局配置相同，此优先级最高，会覆盖在其他地方的相同配置参数
    request.interceptors.request((config) => {
      if (config.isLoading) {
        uni.showLoading({
          title: "正在加载",
          mask: true,
        });
      }
      if (isLogin()) {
        config.header['Authorization'] = getStorage('token');
      } 
      // 返回修改后的配置，如未修改也需添加这行
      // if (config.isToken && isLogin()) {
      //   config.header.Authorization = "Bearer " + util.getToken();
      // }
      return config;
    });


    // 设置响应拦截器
    // 防止多个接口返回401
    // let recordNumber = 0;
    request.interceptors.response((res) => {
      const {
        data = {}, statusCode = 200, config
      } = res;
      uni.hideLoading();
      // 统一处理
      // const message = data?.message || data?.msg || null;
      if (statusCode === 200 && data?.status === 200) {
        return data?.result || true;
      } else {
        reportEvent('api_error', {err_msg: JSON.stringify({...(res || {}), url: config.url, params: config.params })});
        return res.result;
      }  
    });
}
class Request {
  constructor(config = {}) {
    this.config = {};
    this.config.baseUrl = config.baseUrl ? config.baseUrl : '';
    this.config.dataType = config.dataType ? config.dataType : 'json';
    this.config.responseType = config.responseType ? config.responseType : 'text';
    this.config.header = config.header ? config.header : {};
    this.config.localDebug = config.localDebug;
    this.config.hideMsg = config.hideMsg;
    this.reqInterceptors = null;
    this.resInterceptors = null;
    this.interceptors = {
      request: fn => {
        this.reqInterceptors = fn;
      },
      response: fn => {
        this.resInterceptors = fn;
      }
    }
  }
  async get(url, config = {}) {
    return this._request('get', url, config);
  }
  async post(url, config = {}) {
    return this._request('post', url, config);
  }
  async put(url, config = {}) {
    return this._request('put', url, config);
  }
  async delete(url, config = {}) {
    return this._request('delete', url, config);
  }
  setConfig(config = {}) {
    this.config = this._deepCopy(this._merge(this.config, config));
  }
  getConfig() {
    return this.config;
  }
  _request(method, url, config) {
    const _this = this;
    let newConfig = this._deepCopy(this._merge(this.config, config));
    let lastConfig = {};
    if (this.reqInterceptors && typeof this.reqInterceptors === 'function') {
      let reqInterceptors = this.reqInterceptors(newConfig);
      if (!reqInterceptors && process.env.NODE_ENV === "development") {
        console.warn('请求被拦截，此消息仅在开发环境显示。')
        return false;
      } else if (Object.prototype.toString.call(reqInterceptors) === "[object Promise]") {
        return reqInterceptors;
      }
      lastConfig = this._deepCopy(reqInterceptors);
    } else {
      lastConfig = this._deepCopy(newConfig);
    }
    let fullUrl = this._formatUrl(lastConfig.baseUrl, url);

    return new Promise((resolve, reject) => {
      uni.request({
        url: fullUrl,
        method,
        data: lastConfig.data ? lastConfig.data : {},
        header: lastConfig.header,
        dataType: lastConfig.dataType,
        responseType: lastConfig.responseType,
        async complete(response) {
          let res = {...response, config: {hideMsg: config.hideMsg, url, params: lastConfig.data ? lastConfig.data : {}}};
          if (_this.resInterceptors && typeof _this.resInterceptors === 'function') {
            let resInterceptors = _this.resInterceptors(res);
            if (!resInterceptors) {
              reject('返回值已被您拦截！');
              return;
            } else if (Object.prototype.toString.call(resInterceptors) === "[object Promise]") {
              try {
                let promiseRes = await resInterceptors;
                resolve(promiseRes)
              } catch (error) {
                reject(error)
              }
            } else {
              res = resInterceptors;
            }
          }
          resolve(res);
        }
      });
    })
  }
  _formatUrl(baseUrl, url) {
    if (!baseUrl) return url;
    let formatUrl = '';
    const baseUrlEndsWithSlash = baseUrl.endsWith('/');
    const urlStartsWithSlash = url.startsWith('/');
    if (baseUrlEndsWithSlash && urlStartsWithSlash) {
      formatUrl = baseUrl + url.substring(1);
    } else if (baseUrlEndsWithSlash || urlStartsWithSlash) {
      formatUrl = baseUrl + url;
    } else {
      formatUrl = baseUrl + '/' + url;
    }
    if (this.config.localDebug.enable) {
      // 本地联调
      formatUrl = formatUrl.replace(new RegExp(this.config.localDebug.regExp), this.config.localDebug.localAddr);
    }
    return formatUrl;
  }
  _merge(oldConfig, newConfig) {
    let mergeConfig = this._deepCopy(oldConfig);
    if (!newConfig || !Object.keys(newConfig).length) return mergeConfig;
    for (let key in newConfig) {
      if (key !== 'header') {
        mergeConfig[key] = newConfig[key];
      } else {
        if (Object.prototype.toString.call(newConfig[key]) === '[object Object]') {
          for (let headerKey in newConfig[key]) {
            mergeConfig[key][headerKey] = newConfig[key][headerKey];
          }
        }
      }
    }
    return mergeConfig;
  }
  _deepCopy(obj) {
    let result = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (typeof obj[key] === 'object' && obj[key]) {
          result[key] = this._deepCopy(obj[key]);
        } else {
          result[key] = obj[key];
        }
      }
    }
    return result;
  }
}

if (!global.$request) {
  const request = new Request();
  requestSetting(request);
  global.$request = request;
}

export default global.$request;
